package com.example.hetong_system.service;

import com.example.hetong_system.model.*;
import com.example.hetong_system.model.dto.*;
import com.example.hetong_system.model.enums.AuditStatus;
import com.example.hetong_system.model.enums.ContractStatus;
import com.example.hetong_system.repository.*;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayOutputStream;
import java.net.URLEncoder;
import java.net.http.HttpResponse;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;



import com.example.hetong_system.model.Contract;
import com.example.hetong_system.model.Document;
import com.example.hetong_system.model.enums.ContractStatus;
import com.example.hetong_system.repository.ContractRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.List;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

@Service
public class ContractService {

    @Autowired
    private ContractRepository contractRepository;

    @Autowired
    private CustomerRepository customerRepository;

    @Autowired
    private EmployeeRepository employeeRepository;

    @Autowired
    private MilestonePlanRepository milestonePlanRepository;

    @Autowired
    private ClauseService clauseService;  // 条款服务

    @Autowired
    private ContractClauseRepository contractClauseRepository;

    public Contract save(Contract contract) {
        // 保存关联的客户（如果是新客户）
        if (contract.getCustomer() != null && contract.getCustomer().getId() == null) {
            contract.setCustomer(customerRepository.save(contract.getCustomer()));
        }

        // 保存关联的项目经理（如果是新项目经理）
        if (contract.getProjectManager() != null && contract.getProjectManager().getId() == null) {
            contract.setProjectManager(employeeRepository.save(contract.getProjectManager()));
        }

        return contractRepository.save(contract);
    }

    /**
     * 获取合同详情，包含完整的关联对象（项目经理和客户）
     */
    @Transactional // 确保会话在数据处理期间保持打开
    public Optional<Contract> findById(Long id) {
        Optional<Contract> contract = contractRepository.findById(id);
        contract.ifPresent(this::initializeContractRelations);
        return contract;
    }

    /**
     * 根据ID获取合同，包含完整的关联对象
     */
    @Transactional
    public Optional<Contract> getContractById(Long id) {
        Optional<Contract> contract = contractRepository.findById(id);
        contract.ifPresent(this::initializeContractRelations);
        return contract;
    }

    /**
     * 初始化合同的关联对象（项目经理和客户）
     */
    private void initializeContractRelations(Contract contract) {
        // 初始化项目经理信息
        if (contract.getProjectManager() != null) {
            // 访问属性触发懒加载
            contract.getProjectManager().getId();
            contract.getProjectManager().getName();
            contract.getProjectManager().getPosition();
            contract.getProjectManager().getContactInfo();
        }

        // 初始化客户信息
        if (contract.getCustomer() != null) {
            contract.getCustomer().getId();
            contract.getCustomer().getCompanyName();
            contract.getCustomer().getContactName();
            contract.getCustomer().getContactInfo();
        }

        // 初始化条款信息（如果需要）
        if (contract.getContractClauses() != null) {
            contract.getContractClauses().size(); // 触发条款列表的加载
        }
    }

    /**
     * 根据状态获取合同列表，包含完整的关联对象
     */
    @Transactional
    public List<Contract> findByStatus(String status) {
        List<Contract> contracts = contractRepository.findByStatus(status);
        contracts.forEach(this::initializeContractRelations);
        return contracts;
    }

    // 新增方法，返回DTO列表
    @Transactional
    public List<ContractDTO> findByStatusAsDTO(String status) {
        List<Contract> contracts = contractRepository.findByStatus(status);
        return contracts.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    private ContractDTO convertToDTO(Contract contract) {
        ContractDTO dto = new ContractDTO();
        dto.setId(contract.getId());
        dto.setName(contract.getName());
        dto.setStatus(ContractStatus.valueOf(contract.getStatus()));
        dto.setCreateTime(contract.getCreateTime());
        dto.setUpdateTime(contract.getUpdateTime());

        if (contract.getProjectManager() != null) {
            dto.setProjectManagerId(contract.getProjectManager().getId());
            dto.setProjectManagerName(contract.getProjectManager().getName());
            dto.setProjectManagerContactInfo(contract.getProjectManager().getContactInfo());
        }

        if (contract.getCustomer() != null) {
            dto.setCustomerId(contract.getCustomer().getId());
            dto.setCustomerCompanyName(contract.getCustomer().getCompanyName());
            dto.setCustomerContactName(contract.getCustomer().getContactName());
            dto.setCustomerContactInfo(contract.getCustomer().getContactInfo());
        }

        return dto;
    }

    // 创建合同
    @Transactional
    public Contract createContract(Long projectManagerId, String contractName, Long customerId) {
        // 验证项目经理是否存在且职位为项目经理
        Optional<Employee> projectManagerOpt = employeeRepository.findById(projectManagerId);
        if (!projectManagerOpt.isPresent() ||
                !"PROJECT_MANAGER".equals(projectManagerOpt.get().getPosition())) {
            throw new IllegalStateException("只有项目经理可以创建合同");
        }

        // 创建合同
        Contract contract = new Contract();
        contract.setName(contractName);
        contract.setStatus(ContractStatus.DRAFT.name());
        contract.setCreateTime(LocalDateTime.now());
        contract.setUpdateTime(LocalDateTime.now());
        contract.setProjectManager(projectManagerOpt.get());

        // 设置客户
        Optional<Customer> customerOpt = customerRepository.findById(customerId);
        if (customerOpt.isPresent()) {
            contract.setCustomer(customerOpt.get());
        } else {
            throw new IllegalArgumentException("客户不存在，ID: " + customerId);
        }

        return contractRepository.save(contract);
    }

    // 获取所有合同
    @Transactional
    public List<Contract> getAllContracts() {
        List<Contract> contracts = contractRepository.findAll();
        contracts.forEach(this::initializeContractRelations);
        return contracts;
    }

    // 根据项目经理ID获取合同
    @Transactional
    public List<Contract> findByProjectManagerId(Long managerId) {
        List<Contract> contracts = contractRepository.findByProjectManagerId(managerId);
        contracts.forEach(this::initializeContractRelations);
        return contracts;
    }

    // 根据客户ID获取合同
    @Transactional
    public List<Contract> findByCustomerId(Long customerId) {
        List<Contract> contracts = contractRepository.findByCustomerId(customerId);
        contracts.forEach(this::initializeContractRelations);
        return contracts;
    }

    // 创建合同并管理条款
    @Transactional
    public Contract createContractWithClauses(
            Long projectManagerId, String contractName, Long customerId,
            List<Long> existingClauseIds, List<String> newClauseContents) {

        // 创建基本合同
        Contract contract = createContract(projectManagerId, contractName, customerId);

        // 处理已有条款
        if (existingClauseIds != null && !existingClauseIds.isEmpty()) {
            for (Long clauseId : existingClauseIds) {
                clauseService.associateClauseWithContract(contract.getId(), clauseId, "INITIAL");
            }
        }

        // 处理新条款
        if (newClauseContents != null && !newClauseContents.isEmpty()) {
            for (String content : newClauseContents) {
                Clause clause = clauseService.createClause(content);
                clauseService.associateClauseWithContract(contract.getId(), clause.getId(), "INITIAL");
            }
        }

        return contract;
    }

    /**
     * 获取待提交合同数量
     */
    @Transactional
    public Long getPendingSubmitContractCount(Long employeeId) {
        Employee employee = employeeRepository.findById(employeeId)
                .orElse(null);

        if (employee == null) {
            return 0L;
        }

        // 验证是否为项目经理
        if (!"PROJECT_MANAGER".equals(employee.getPosition())) {
            return 0L;
        }

        // 使用枚举的code属性而不是枚举对象
        return contractRepository.countByProjectManagerAndStatus(
                employee, ContractStatus.DRAFT.getCode());
    }

    /**
     * 获取待修订合同数量
     */
    @Transactional
    public Long getPendingRevisionContractCount(Long employeeId) {
        Employee employee = employeeRepository.findById(employeeId)
                .orElse(null);

        if (employee == null) {
            return 0L;
        }

        // 验证是否为项目经理
        if (!"PROJECT_MANAGER".equals(employee.getPosition())) {
            return 0L;
        }

        return contractRepository.countByProjectManagerAndStatus(
                employee, ContractStatus.REVIEW_FAILED.getCode());
    }

    /**
     * 获取已完成合同数量
     */
    @Transactional
    public Long getCompletedContractCount(Long employeeId) {
        Employee employee = employeeRepository.findById(employeeId)
                .orElse(null);

        if (employee == null) {
            return 0L;
        }

        return contractRepository.countByProjectManagerAndStatus(
                employee, ContractStatus.COMPLETED.getCode());
    }


//    /**
//     * 获取待提交合同列表（带分页）
//     */
//    @Transactional(readOnly = true)
//    public Page<ContractDTO> getPendingSubmitContracts(Long employeeId, Pageable pageable) {
//        Employee employee = employeeRepository.findById(employeeId)
//                .orElseThrow(() -> new IllegalArgumentException("员工不存在，ID: " + employeeId));
//
//        // 验证是否为项目经理
//        if (!"PROJECT_MANAGER".equals(employee.getPosition())) {
//            throw new IllegalStateException("只有项目经理可以查看待提交合同");
//        }
//
//        Page<Contract> contracts = contractRepository.findByProjectManagerAndStatus(
//                employee, ContractStatus.DRAFT.getCode(), pageable);
//
//        return contracts.map(this::convertToDTO);
//    }
@Transactional(readOnly = true)
public Page<ContractDTO> getPendingSubmitContracts(Long employeeId, Pageable pageable) {
    Employee employee = employeeRepository.findById(employeeId)
            .orElseThrow(() -> new IllegalArgumentException("员工不存在，ID: " + employeeId));

    // 验证是否为项目经理
    if (!"PROJECT_MANAGER".equals(employee.getPosition())) {
        throw new IllegalStateException("只有项目经理可以查看待提交合同");
    }

    // 获取DRAFT和REVIEW_FAILED状态的合同
    List<String> statusCodes = Arrays.asList(
            ContractStatus.DRAFT.getCode(),
            ContractStatus.REVIEW_FAILED.getCode()
    );

    Page<Contract> contracts = contractRepository.findByProjectManagerAndStatusIn(
            employee, statusCodes, pageable
    );

    return contracts.map(this::convertToDTO);
}

    /**
     * 获取待修订合同列表（带分页）
     */
    @Transactional(readOnly = true)
    public Page<ContractDTO> getPendingRevisionContracts(Long employeeId, Pageable pageable) {
        Employee employee = employeeRepository.findById(employeeId)
                .orElseThrow(() -> new IllegalArgumentException("员工不存在，ID: " + employeeId));

        // 验证是否为项目经理
        if (!"PROJECT_MANAGER".equals(employee.getPosition())) {
            throw new IllegalStateException("只有项目经理可以查看待修订合同");
        }

        Page<Contract> contracts = contractRepository.findByProjectManagerAndStatus(
                employee, ContractStatus.REVIEW_FAILED.getCode(), pageable);

        return contracts.map(this::convertToDTO);
    }

    /**
     * 提交合同进行审核
     */
//    @Transactional
//    public void submitContractForReview(Long contractId, Long employeeId) {
//        Contract contract = contractRepository.findById(contractId)
//                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + contractId));
//
//        Employee employee = employeeRepository.findById(employeeId)
//                .orElseThrow(() -> new IllegalArgumentException("员工不存在，ID: " + employeeId));
//
//        // 验证是否为合同的项目经理
//        if (!contract.getProjectManager().getId().equals(employeeId)) {
//            throw new IllegalStateException("只有合同的项目经理可以提交审核");
//        }
//
//        // 更新合同状态为待审核
//        contract.setStatus(ContractStatus.PENDING_REVIEW.getCode());
//        contractRepository.save(contract);
//    }
    @Transactional
    public void submitContractForReview(Long contractId, Long employeeId) {
        Contract contract = contractRepository.findById(contractId)
                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + contractId));

        Employee employee = employeeRepository.findById(employeeId)
                .orElseThrow(() -> new IllegalArgumentException("员工不存在，ID: " + employeeId));

        // 验证是否为合同的项目经理
        if (!contract.getProjectManager().getId().equals(employeeId)) {
            throw new IllegalStateException("只有合同的项目经理可以提交审核");
        }

        // 更新合同状态为待审核
        contract.setStatus(ContractStatus.PENDING_REVIEW.getCode());
        contractRepository.save(contract);

        // 查询所有相关条款
        List<ContractClause> clauses = contractClauseRepository.findByContractId(contractId);

        // 检查所有条款的审核状态
        boolean allApproved = clauses.stream()
                .allMatch(clause ->
                        AuditStatus.APPROVED.equals(clause.getLegalAuditStatus()) &&
                                AuditStatus.APPROVED.equals(clause.getFinanceAuditStatus()) &&
                                AuditStatus.APPROVED.equals(clause.getCustomerAuditStatus())
                );

        // 如果所有条款都为APPROVED，则更新合同状态为PENDING_CONFIRMATION
        if (allApproved) {
            contract.setStatus(ContractStatus.PENDING_CONFIRMATION.getCode());
            contractRepository.save(contract);
        }
    }

    /**
     * 获取待审核合同数量
     */
    @Transactional(readOnly = true)
    public Long getPendingAuditContractCount(Long employeeId, String position) {
        // 确定审核类型
        boolean isLegalAudit = "LEGAL_SPECIALIST".equals(position);

        // 传递AuditStatus.PENDING作为第二个参数
        return contractClauseRepository.countByAuditStatus(
                isLegalAudit, AuditStatus.PENDING);
    }

    /**
     * 获取待审核合同列表（带分页）
     */
    @Transactional(readOnly = true)
    public Page<Contract> getPendingAuditContracts(Long employeeId, String position, String type, Pageable pageable) {
        boolean isLegalAudit = "legal".equals(type);

        // 传递AuditStatus.PENDING作为第三个参数
        return contractClauseRepository.findContractsWithPendingAudit(
                isLegalAudit, AuditStatus.PENDING, pageable);
    }

    /**
     * 获取合同审核详情
     */
    @Transactional(readOnly = true)
    public ContractAuditDTO getContractForAudit(Long contractId, String type) {
        boolean isLegalAudit = "legal".equals(type);

        Optional<Contract> contractOpt = contractRepository.findById(contractId);
        if (!contractOpt.isPresent()) {
            throw new IllegalArgumentException("合同不存在，ID: " + contractId);
        }

        Contract contract = contractOpt.get();

        // 使用分页查询条款并返回完整结果
        Pageable pageable = PageRequest.of(0, 100); // 获取所有条款（假设最多100条）
        Page<ContractClause> clausesPage;

        if (isLegalAudit) {
            clausesPage = contractClauseRepository.findByContractIdAndLegalAuditStatus(
                    contractId, AuditStatus.PENDING, pageable);
        } else {
            clausesPage = contractClauseRepository.findByContractIdAndFinanceAuditStatus(
                    contractId, AuditStatus.PENDING, pageable);
        }

        return new ContractAuditDTO(
                contract,
                clausesPage.getContent().stream()
                        .map(clause -> {
                            ContractClauseAuditDTO clauseDTO = new ContractClauseAuditDTO();
                            clauseDTO.setId(clause.getId().getClauseId()); // 正确设置条款ID
                            clauseDTO.setContent(clause.getClause().getContent());
                            clauseDTO.setAuditStatus(String.valueOf(isLegalAudit ?
                                    clause.getLegalAuditStatus() : clause.getFinanceAuditStatus()));
                            clauseDTO.setAuditStatusDisplayName(isLegalAudit ?
                                    clause.getLegalAuditStatus().getDisplayName() :
                                    clause.getFinanceAuditStatus().getDisplayName());
                            clauseDTO.setType(type); // 设置审核类型
                            return clauseDTO;
                        })
                        .collect(Collectors.toList()),
                clausesPage.getTotalPages(),
                clausesPage.getTotalElements()
        );
    }

    /**
     * 获取条款审核详情
     */
    @Transactional(readOnly = true)
    public ContractClauseAuditDTO getClauseForAudit(Long contractId, Long clauseId, String type) {
        boolean isLegalAudit = "legal".equals(type);

        // 使用复合主键查询
        Optional<ContractClause> contractClauseOpt = contractClauseRepository.findById(
                new ContractClauseId(contractId, clauseId));
        if (!contractClauseOpt.isPresent()) {
            throw new IllegalArgumentException("条款不存在，合同ID: " + contractId + ", 条款ID: " + clauseId);
        }

        ContractClause contractClause = contractClauseOpt.get();
        ContractClauseAuditDTO clauseDTO = new ContractClauseAuditDTO();

        clauseDTO.setId(contractClause.getId().getClauseId());
        clauseDTO.setContent(contractClause.getClause().getContent());
        clauseDTO.setAuditStatus(String.valueOf(isLegalAudit ?
                contractClause.getLegalAuditStatus() : contractClause.getFinanceAuditStatus()));
        clauseDTO.setAuditStatusDisplayName(isLegalAudit ?
                contractClause.getLegalAuditStatus().getDisplayName() :
                contractClause.getFinanceAuditStatus().getDisplayName());
        clauseDTO.setType(type);

        return clauseDTO;
    }

//    /**
//     * 提交条款审核
//     */
//    @Transactional
//    public void submitClauseAudit(Long contractId, Long clauseId,
//                                  ContractClauseAuditDTO auditDTO, Long employeeId) {
//        // 使用复合主键查询
//        Optional<ContractClause> contractClauseOpt = contractClauseRepository.findById(
//                new ContractClauseId(contractId, clauseId));
//        if (!contractClauseOpt.isPresent()) {
//            throw new IllegalArgumentException("条款不存在，合同ID: " + contractId + ", 条款ID: " + clauseId);
//        }
//
//        ContractClause contractClause = contractClauseOpt.get();
//        boolean isLegalAudit = "legal".equals(auditDTO.getType());
//
//        if (isLegalAudit) {
//            contractClause.setLegalAuditStatus(AuditStatus.valueOf(auditDTO.getAuditStatus()));
//            contractClause.setLegalOpinion(auditDTO.getOpinion());
//        } else {
//            contractClause.setFinanceAuditStatus(AuditStatus.valueOf(auditDTO.getAuditStatus()));
//            contractClause.setFinanceOpinion(auditDTO.getOpinion());
//        }
//
//        contractClauseRepository.save(contractClause);
//
//        // 检查是否所有条款已审核
//        List<ContractClause> clauses = contractClauseRepository.findByContractId(contractId);
//        boolean allClausesAudited = clauses.stream()
//                .allMatch(clause -> {
//                    if (isLegalAudit) {
//                        return clause.getLegalAuditStatus() != AuditStatus.PENDING;
//                    } else {
//                        return clause.getFinanceAuditStatus() != AuditStatus.PENDING;
//                    }
//                });
//
//        if (allClausesAudited) {
//            Contract contract = contractRepository.findById(contractId)
//                    .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + contractId));
//
//            if (isLegalAudit) {
//                contract.setStatus("PENDING_FINANCE_AUDIT"); // 法务审核完成，等待财务审核
//            } else {
//                contract.setStatus("APPROVED"); // 财务审核完成，合同批准
//            }
//
//            contractRepository.save(contract);
//        }
//    }

    /**
     * 获取待客户审核合同数量
     */
    @Transactional(readOnly = true)
    public Long getPendingCustomerAuditContractCount(Long customerId) {
        return contractClauseRepository.countByCustomerAuditStatusAndCustomer(
                AuditStatus.PENDING, customerId);
    }

    /**
     * 获取待客户审核合同列表（带分页）
     */
    @Transactional(readOnly = true)
    public Page<Contract> getPendingCustomerAuditContracts(Long customerId, Pageable pageable) {
        return contractClauseRepository.findContractsWithPendingCustomerAudit(
                customerId, AuditStatus.PENDING, pageable);
    }

    /**
     * 获取合同客户审核详情
     */
    @Transactional(readOnly = true)
    public ContractCustomerAuditDTO getContractForCustomerAudit(Long contractId) {
        Optional<Contract> contractOpt = contractRepository.findById(contractId);
        if (!contractOpt.isPresent()) {
            throw new IllegalArgumentException("合同不存在，ID: " + contractId);
        }

        Contract contract = contractOpt.get();
        Pageable pageable = PageRequest.of(0, 100);
        Page<ContractClause> clausesPage = contractClauseRepository.findByContractIdAndCustomerAuditStatus(
                contractId, AuditStatus.PENDING, pageable);

        List<ContractClauseAuditDTO> clauseDTOs = clausesPage.getContent().stream()
                .map(clause -> {
                    ContractClauseAuditDTO clauseDTO = new ContractClauseAuditDTO();
                    clauseDTO.setId(clause.getId().getClauseId());
                    clauseDTO.setContent(clause.getClause().getContent());
                    clauseDTO.setAuditStatus(clause.getCustomerAuditStatus().name());
                    clauseDTO.setAuditStatusDisplayName(clause.getCustomerAuditStatus().getDisplayName());
                    clauseDTO.setType(clause.getType()); // 设置条款类型
                    return clauseDTO;
                })
                .collect(Collectors.toList());

        return new ContractCustomerAuditDTO(
                contract,
                clauseDTOs,
                clausesPage.getTotalPages(),
                clausesPage.getTotalElements()
        );
    }

    /**
     * 获取条款客户审核详情
     */
    @Transactional(readOnly = true)
    public ContractClauseAuditDTO getClauseForCustomerAudit(Long contractId, Long clauseId) {
        Optional<ContractClause> contractClauseOpt = contractClauseRepository.findById(
                new ContractClauseId(contractId, clauseId));
        if (!contractClauseOpt.isPresent()) {
            throw new IllegalArgumentException("条款不存在，合同ID: " + contractId + ", 条款ID: " + clauseId);
        }

        ContractClause contractClause = contractClauseOpt.get();
        ContractClauseAuditDTO clauseDTO = new ContractClauseAuditDTO();

        clauseDTO.setId(contractClause.getId().getClauseId());
        clauseDTO.setContent(contractClause.getClause().getContent());
        clauseDTO.setAuditStatus(contractClause.getCustomerAuditStatus().name());
        clauseDTO.setAuditStatusDisplayName(contractClause.getCustomerAuditStatus().getDisplayName());
        clauseDTO.setType(contractClause.getType()); // 设置条款类型

        return clauseDTO;
    }

//    /**
//     * 提交条款客户审核
//     */
//    @Transactional
//    public void submitCustomerClauseAudit(Long contractId, Long clauseId,
//                                          ContractClauseAuditDTO auditDTO, Long customerId) {
//        Optional<ContractClause> contractClauseOpt = contractClauseRepository.findById(
//                new ContractClauseId(contractId, clauseId));
//        if (!contractClauseOpt.isPresent()) {
//            throw new IllegalArgumentException("条款不存在");
//        }
//
//        ContractClause contractClause = contractClauseOpt.get();
//        Customer customer = customerRepository.findById(customerId)
//                .orElseThrow(() -> new IllegalArgumentException("客户不存在"));
//
//        // 设置审核状态和意见
//        contractClause.setCustomerAuditStatus(AuditStatus.valueOf(auditDTO.getAuditStatus()));
//        contractClause.setCustomerOpinion(auditDTO.getOpinion());
//
//        // 保存修改
//        contractClauseRepository.save(contractClause);
//
//        // 检查是否所有条款已审核
//        List<ContractClause> clauses = contractClauseRepository.findByContractId(contractId);
//        boolean allClausesAudited = clauses.stream()
//                .allMatch(clause -> clause.getCustomerAuditStatus() != AuditStatus.PENDING);
//
//        if (allClausesAudited) {
//            Contract contract = contractRepository.findById(contractId)
//                    .orElseThrow(() -> new IllegalArgumentException("合同不存在"));
//            // 所有条款审核完成，更新合同状态
//            contract.setStatus(ContractStatus.CONFIRMED.getCode());
//            contractRepository.save(contract);
//        }
//    }


    /**
     * 提交条款审核
     */
    @Transactional
    public void submitClauseAudit(Long contractId, Long clauseId,
                                  ContractClauseAuditDTO auditDTO, Long employeeId) {
        // 原有逻辑不变
        Optional<ContractClause> contractClauseOpt = contractClauseRepository.findById(
                new ContractClauseId(contractId, clauseId));
        if (!contractClauseOpt.isPresent()) {
            throw new IllegalArgumentException("条款不存在，合同ID: " + contractId + ", 条款ID: " + clauseId);
        }

        ContractClause contractClause = contractClauseOpt.get();
        boolean isLegalAudit = "legal".equals(auditDTO.getType());

        if (isLegalAudit) {
            contractClause.setLegalAuditStatus(AuditStatus.valueOf(auditDTO.getAuditStatus()));
            contractClause.setLegalOpinion(auditDTO.getOpinion());
        } else {
            contractClause.setFinanceAuditStatus(AuditStatus.valueOf(auditDTO.getAuditStatus()));
            contractClause.setFinanceOpinion(auditDTO.getOpinion());
        }

        contractClauseRepository.save(contractClause);

        // 新增：审核后更新合同状态
        updateContractStatus(contractId);
    }

    /**
     * 提交条款客户审核
     */
    @Transactional
    public void submitCustomerClauseAudit(Long contractId, Long clauseId,
                                          ContractClauseAuditDTO auditDTO, Long customerId) {
        // 原有逻辑不变
        Optional<ContractClause> contractClauseOpt = contractClauseRepository.findById(
                new ContractClauseId(contractId, clauseId));
        if (!contractClauseOpt.isPresent()) {
            throw new IllegalArgumentException("条款不存在");
        }

        ContractClause contractClause = contractClauseOpt.get();
        Customer customer = customerRepository.findById(customerId)
                .orElseThrow(() -> new IllegalArgumentException("客户不存在"));

        contractClause.setCustomerAuditStatus(AuditStatus.valueOf(auditDTO.getAuditStatus()));
        contractClause.setCustomerOpinion(auditDTO.getOpinion());

        contractClauseRepository.save(contractClause);

        // 新增：审核后更新合同状态
        updateContractStatus(contractId);
    }

    /**
     * 审核后更新合同状态核心逻辑
     */
    private void updateContractStatus(Long contractId) {
        // 查询合同所有条款
        List<ContractClause> clauses = contractClauseRepository.findByContractId(contractId);
        if (clauses.isEmpty()) return;

        boolean allApproved = true;
        boolean hasRejected = false;
        boolean hasPending = false;

        // 检查所有条款的审核状态
        for (ContractClause clause : clauses) {
            // 检查法务审核状态
            if (clause.getLegalAuditStatus() == AuditStatus.PENDING) {
                hasPending = true;
                allApproved = false;
            } else if (clause.getLegalAuditStatus() == AuditStatus.REJECTED) {
                hasRejected = true;
                allApproved = false;
            }

            // 检查财务审核状态
            if (clause.getFinanceAuditStatus() == AuditStatus.PENDING) {
                hasPending = true;
                allApproved = false;
            } else if (clause.getFinanceAuditStatus() == AuditStatus.REJECTED) {
                hasRejected = true;
                allApproved = false;
            }

            // 检查客户审核状态
            if (clause.getCustomerAuditStatus() == AuditStatus.PENDING) {
                hasPending = true;
                allApproved = false;
            } else if (clause.getCustomerAuditStatus() == AuditStatus.REJECTED) {
                hasRejected = true;
                allApproved = false;
            }

            // 提前终止检查
            if (!allApproved && hasRejected) break;
        }

        // 更新合同状态
        Optional<Contract> contractOpt = contractRepository.findById(contractId);
        if (contractOpt.isPresent()) {
            Contract contract = contractOpt.get();
            if (allApproved) {
                contract.setStatus(ContractStatus.PENDING_CONFIRMATION.getCode());
            } else if (!hasPending && hasRejected) {
                contract.setStatus(ContractStatus.REVIEW_FAILED.getCode());
            }
            contractRepository.save(contract);
        }
    }

    // 根据客户ID获取合同（带分页）
    @Transactional(readOnly = true)
    public Page<Contract> findByCustomerId(Long customerId, Pageable pageable) {
        Customer customer = customerRepository.findById(customerId)
                .orElseThrow(() -> new IllegalArgumentException("客户不存在，ID: " + customerId));

        Page<Contract> contracts = contractRepository.findByCustomer(customer, pageable);
        contracts.forEach(this::initializeContractRelations);
        return contracts;
    }

    // 获取指定项目经理的所有合同（带分页）
    public Page<Contract> getContractsByManagerId(Long managerId, Pageable pageable) {
        Employee manager = employeeRepository.findById(managerId)
                .orElseThrow(() -> new IllegalArgumentException("项目经理不存在，ID: " + managerId));

        // 直接使用您已有的方法
        return contractRepository.findByProjectManagerAndStatus(manager, null, pageable);
    }




    private DocumentRepository documentRepository;
    private static final String FILE_STORAGE_DIR = "D:/LUT/Web_Project/Hetong_System/src/main/java/cangku/";

    public ContractService(ContractRepository contractRepository, DocumentRepository documentRepository) {
        this.contractRepository = contractRepository;
        this.documentRepository = documentRepository;
    }

    // 在ContractService.java中修改相关方法的参数类型
    public List<Contract> getPendingSignContracts(Long managerId, int page, int size) {
        // 参数验证
        if (page < 0 || size <= 0) {
            throw new IllegalArgumentException("分页参数错误，page必须>=0，size必须>0");
        }

        // 验证项目经理是否存在
        Employee manager = employeeRepository.findById(managerId)
                .orElseThrow(() -> new IllegalArgumentException("项目经理不存在，ID: " + managerId));

        PageRequest pageRequest = PageRequest.of(page, size);
        // 修改：传递ContractStatus的name()作为字符串
        return contractRepository.findByProjectManagerIdAndStatus(
                managerId,
                ContractStatus.PENDING_CONFIRMATION.name(),  // 使用枚举的name()作为字符串
                pageRequest
        ).getContent();
    }

    public Long getPendingSignContractCount(Long managerId) {
        // 参数验证
        if (managerId == null) {
            throw new IllegalArgumentException("经理ID不能为空");
        }

        // 验证项目经理是否存在
        Employee manager = employeeRepository.findById(managerId)
                .orElseThrow(() -> new IllegalArgumentException("项目经理不存在，ID: " + managerId));

        // 修改：传递ContractStatus的name()作为字符串
        return contractRepository.countByProjectManagerIdAndStatus(
                managerId,
                ContractStatus.PENDING_CONFIRMATION.name()  // 使用枚举的name()作为字符串
        );
    }

//    // 生成合同PDF (实际项目中需要集成PDF生成库如iText)
//    public byte[] generateContractPdf(Long contractId) {
//        // 验证合同是否存在
//        Contract contract = contractRepository.findById(contractId)
//                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + contractId));
//
//        // 实际项目中这里会使用PDF生成库将合同内容转为PDF
//        // 简化示例：返回空字节数组
//        return new byte[0];
//    }




    // iText 7,利用html转pdf,学到了>w<666啊
    public byte[] generateContractPdf(Long contractId) {
    // 验证合同是否存在
    Contract contract = contractRepository.findById(contractId)
            .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + contractId));

    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    // 创建PDF文档和写入器
    com.itextpdf.kernel.pdf.PdfWriter writer = new com.itextpdf.kernel.pdf.PdfWriter(baos);
    com.itextpdf.kernel.pdf.PdfDocument pdfDoc = new com.itextpdf.kernel.pdf.PdfDocument(writer);
    com.itextpdf.layout.Document document = new com.itextpdf.layout.Document(pdfDoc, com.itextpdf.kernel.geom.PageSize.A4);
    document.setMargins(50, 50, 50, 50);

    try {
        // 加载中文字体
        PdfFont font = PdfFontFactory.createFont(
                "STSongStd-Light",
                "UniGB-UCS2-H",
                PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED
        );

        // 定义不同用途的字体大小
        float titleSize = 18;
        float subtitleSize = 14;
        float normalSize = 12;
        float tableHeaderSize = 11;
        float tableContentSize = 11;

        // 添加标题
        com.itextpdf.layout.element.Paragraph title = new com.itextpdf.layout.element.Paragraph("合同详情")
                .setFont(font)
                .setFontSize(titleSize)
                .setBold()
                .setTextAlignment(com.itextpdf.layout.properties.TextAlignment.CENTER)
                .setMarginBottom(20);
        document.add(title);

        // 添加合同基本信息标题
        document.add(new com.itextpdf.layout.element.Paragraph("合同基本信息")
                .setFont(font)
                .setFontSize(subtitleSize)
                .setBold());
        document.add(new com.itextpdf.layout.element.Paragraph("")); // 空行

        // 创建基本信息表格
        float[] columnWidths = {1, 2};
        com.itextpdf.layout.element.Table infoTable = new com.itextpdf.layout.element.Table(columnWidths)
                .useAllAvailableWidth()
                .setMarginBottom(15);

        addTableHeaderCell(infoTable, "合同ID:", font, tableHeaderSize);
        addTableCell(infoTable, contract.getId().toString(), font, tableContentSize);

        addTableHeaderCell(infoTable, "合同名称:", font, tableHeaderSize);
        addTableCell(infoTable, contract.getName(), font, tableContentSize);

        addTableHeaderCell(infoTable, "客户:", font, tableHeaderSize);
        addTableCell(infoTable, contract.getCustomer() != null ? contract.getCustomer().getCompanyName() : "未选择", font, tableContentSize);

        addTableHeaderCell(infoTable, "项目经理:", font, tableHeaderSize);
        addTableCell(infoTable, contract.getProjectManager() != null ? contract.getProjectManager().getName() : "未指定", font, tableContentSize);

        addTableHeaderCell(infoTable, "合同状态:", font, tableHeaderSize);
        addTableCell(infoTable, contract.getStatus(), font, tableContentSize);

        addTableHeaderCell(infoTable, "创建时间:", font, tableHeaderSize);
        addTableCell(infoTable, contract.getCreateTime().toString(), font, tableContentSize);

        addTableHeaderCell(infoTable, "更新时间:", font, tableHeaderSize);
        addTableCell(infoTable, contract.getUpdateTime().toString(), font, tableContentSize);

        document.add(infoTable);

        // 添加合同条款
        if (contract.getContractClauses() != null && !contract.getContractClauses().isEmpty()) {
            document.add(new com.itextpdf.layout.element.Paragraph("合同条款")
                    .setFont(font)
                    .setFontSize(subtitleSize)
                    .setBold());
            document.add(new com.itextpdf.layout.element.Paragraph("")); // 空行

            com.itextpdf.layout.element.Table clauseTable = new com.itextpdf.layout.element.Table(1)
                    .useAllAvailableWidth()
                    .setMarginBottom(15);

            int clauseNum = 1;
            for (ContractClause contractClause : contract.getContractClauses()) {
                addTableHeaderCell(clauseTable, "条款 " + clauseNum + ":", font, tableHeaderSize);
                addTableCell(clauseTable, contractClause.getClause().getContent(), font, tableContentSize);
                clauseNum++;
            }

            document.add(clauseTable);
        }

        document.close();
    } catch (java.io.IOException e) {
        e.printStackTrace();
    }

    return baos.toByteArray();
    }
    // 辅助方法：添加表格头部单元格
    private void addTableHeaderCell(
            com.itextpdf.layout.element.Table table,
            String content,
            com.itextpdf.kernel.font.PdfFont font,
            float fontSize) {

        com.itextpdf.layout.element.Cell cell = new com.itextpdf.layout.element.Cell()
                .add(new com.itextpdf.layout.element.Paragraph(content)
                        .setFont(font)
                        .setFontSize(fontSize)
                        .setBold())
                .setPadding(5)
                .setVerticalAlignment(com.itextpdf.layout.properties.VerticalAlignment.MIDDLE)
                .setHorizontalAlignment(com.itextpdf.layout.properties.HorizontalAlignment.RIGHT);

        table.addCell(cell);
    }
    // 辅助方法：添加表格内容单元格
    private void addTableCell(
            com.itextpdf.layout.element.Table table,
            String content,
            com.itextpdf.kernel.font.PdfFont font,
            float fontSize) {

        com.itextpdf.layout.element.Cell cell = new com.itextpdf.layout.element.Cell()
                .add(new com.itextpdf.layout.element.Paragraph(content)
                        .setFont(font)
                        .setFontSize(fontSize))
                .setPadding(5)
                .setVerticalAlignment(com.itextpdf.layout.properties.VerticalAlignment.MIDDLE)
                .setHorizontalAlignment(com.itextpdf.layout.properties.HorizontalAlignment.LEFT);

        table.addCell(cell);
    }



    // 确认签订合同
//    public void signContract(Long contractId, MultipartFile file) throws IOException {
//        // 1. 验证合同是否存在
//        Contract contract = contractRepository.findById(contractId)
//                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + contractId));
//
//        // 2. 验证合同状态是否为待签订
//        if (!ContractStatus.PENDING_CONFIRMATION.name().equals(contract.getStatus())) {
//            throw new IllegalArgumentException("合同状态不是待签订，无法执行此操作");
//        }
//
//        // 3. 验证文件是否为空
//        if (file == null || file.isEmpty()) {
//            throw new IllegalArgumentException("上传的文件不能为空");
//        }
//
//        // 4. 保存上传的PDF文件
//        String fileName = file.getOriginalFilename();
//        if (fileName == null || fileName.isEmpty()) {
//            fileName = "contract_" + contractId + ".pdf";
//        }
//
//        Path filePath = Paths.get(FILE_STORAGE_DIR, fileName);
//        Files.createDirectories(filePath.getParent());
//        Files.write(filePath, file.getBytes());
//
//        // 5. 创建Document记录
//        Document document = new Document();
//        document.setType(233); // 233表示签订合同
//        document.setContract(contract);
//        document.setUploadTime(LocalDateTime.now());
//        document.setFilePath(filePath.toString());
//        documentRepository.save(document);
//
//        // 6. 更新合同状态
////        contract.setStatus(ContractStatus.CONFIRMED.name());
////        contract.setUpdateTime(LocalDateTime.now());
////        contractRepository.save(contract);
//    }


//    // 短信API配置
//    private static final String SMS_API_HOST = "http://api.guoyangyun.com";
//    private static final String SMS_API_PATH = "/api/sms/sendSmsApi.htm";
//    private static final String SMS_APP_KEY = "204920215";
//    private static final String SMS_APP_SECRET = "KOfZfMetxJcykFQu5Zk97W5vvrDQDfr7";
////    private static final String SMS_SIGNATURE = "9c4d7c6f6a5144ce9cf1305235d2f731";
//
//    public void signContract(Long contractId, MultipartFile file) throws IOException {
//        // 1. 验证合同是否存在
//        Contract contract = contractRepository.findById(contractId)
//                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + contractId));
//
//        // 2. 验证合同状态
//        if (!ContractStatus.PENDING_CONFIRMATION.name().equals(contract.getStatus())) {
//            throw new IllegalArgumentException("合同状态不是待签订，无法执行此操作");
//        }
//
//        // 3. 验证文件
//        if (file == null || file.isEmpty()) {
//            throw new IllegalArgumentException("上传的文件不能为空");
//        }
//
//        // 4. 保存文件
//        String fileName = file.getOriginalFilename();
//        if (fileName == null || fileName.isEmpty()) {
//            fileName = "contract_" + contractId + ".pdf";
//        }
//
//        Path filePath = Paths.get(FILE_STORAGE_DIR, fileName);
//        Files.createDirectories(filePath.getParent());
//        Files.write(filePath, file.getBytes());
//
//        // 5. 创建Document记录
//        Document document = new Document();
//        document.setType(233);
//        document.setContract(contract);
//        document.setUploadTime(LocalDateTime.now());
//        document.setFilePath(filePath.toString());
//        documentRepository.save(document);
//
//        // 新增：发送短信通知
//        sendSmsNotification(contract);
//
//        // 6. 更新合同状态（保持注释）
////        contract.setStatus(ContractStatus.CONFIRMED.name());
////        contract.setUpdateTime(LocalDateTime.now());
////        contractRepository.save(contract);
//    }
//
//    private void sendSmsNotification(Contract contract) {
//        // 获取客户信息
//        Long contractId = contract.getId();
//        if (contractId == null) {
//            System.err.println("合同ID为空，无法查询客户信息");
//            return;
//        }
//
//        // 2. 调用新增的CustomerRepository方法：根据合同ID查询客户
//        Customer customer = customerRepository.findByContractId(contractId)
//                .orElseGet(() -> {
//                    System.err.println("未查询到合同对应的客户，合同ID: " + contractId);
//                    return null;
//                });
//
//        if (customer == null || StringUtils.isBlank(customer.getContactInfo())) {
//            System.err.println("客户联系信息不完整，无法发送短信");
//            return;
//        }
//
//        // 准备短信内容
//        String phone = customer.getContactInfo();
////        String message = SMS_SIGNATURE + "您的合同（" + contract.getName() + "）已上传，待确认";
//        String message = "您的合同（" + contract.getName() + "）已上传，待确认";
//
//        // 构建参数
//        Map<String, String> params = new HashMap<>();
//        params.put("appkey", SMS_APP_KEY);
//        params.put("appsecret", SMS_APP_SECRET);
//        params.put("mobile", phone);
//        params.put("content", message);
//
//        // 发送请求
//        try {
//            // 使用点符号声明HttpClient
//            org.apache.http.client.HttpClient client = org.apache.http.impl.client.HttpClients.createDefault();
//
//            // 使用点符号声明HttpPost
//            org.apache.http.client.methods.HttpPost post = new org.apache.http.client.methods.HttpPost(
//                    buildApiUrl(SMS_API_HOST, SMS_API_PATH, null)
//            );
//
//            // 使用点符号声明参数列表和实体
//            java.util.List<org.apache.http.NameValuePair> formParams = new java.util.ArrayList<>();
//            for (Map.Entry<String, String> entry : params.entrySet()) {
//                formParams.add(new org.apache.http.message.BasicNameValuePair(entry.getKey(), entry.getValue()));
//            }
//
//            org.apache.http.client.entity.UrlEncodedFormEntity formEntity =
//                    new org.apache.http.client.entity.UrlEncodedFormEntity(formParams, "UTF-8");
//            formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
//            post.setEntity(formEntity);
//
//            // 执行请求并处理响应
//            org.apache.http.HttpResponse response = client.execute(post);
//
//            // 处理响应内容
//            if (response != null && response.getEntity() != null) {
//                String result = org.apache.http.util.EntityUtils.toString(response.getEntity());
//                System.out.println("短信发送结果: " + result);
//                org.apache.http.util.EntityUtils.consume(response.getEntity());
//            }
//        } catch (Exception e) {
//            System.err.println("短信发送失败: " + e.getMessage());
//        }
//    }
//
//    private String buildApiUrl(String host, String path, Map<String, String> queryParams) throws UnsupportedEncodingException {
//        StringBuilder url = new StringBuilder(host);
//        if (StringUtils.isNotBlank(path)) {
//            url.append(path);
//        }
//
//        if (queryParams != null && !queryParams.isEmpty()) {
//            StringBuilder query = new StringBuilder();
//            for (Map.Entry<String, String> param : queryParams.entrySet()) {
//                if (query.length() > 0) {
//                    query.append("&");
//                }
//                query.append(param.getKey()).append("=")
//                        .append(URLEncoder.encode(param.getValue(), "UTF-8"));
//            }
//            url.append("?").append(query);
//        }
//        return url.toString();
//    }
//
//    // 依赖注入方法
//    public void setContractRepository(ContractRepository contractRepository) {
//        this.contractRepository = contractRepository;
//    }
//
//    public void setDocumentRepository(DocumentRepository documentRepository) {
//        this.documentRepository = documentRepository;
//    }
//
//
//    // 独立实现URL构建方法（不依赖GeneralSend）
//    private String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
//        StringBuilder sbUrl = new StringBuilder(host);
//        if (StringUtils.isNotBlank(path)) {
//            sbUrl.append(path);
//        }
//        if (querys != null && !querys.isEmpty()) {
//            StringBuilder sbQuery = new StringBuilder();
//            for (Map.Entry<String, String> entry : querys.entrySet()) {
//                if (sbQuery.length() > 0) {
//                    sbQuery.append("&");
//                }
//                if (StringUtils.isBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue())) {
//                    sbQuery.append(entry.getValue());
//                }
//                if (StringUtils.isNotBlank(entry.getKey())) {
//                    sbQuery.append(entry.getKey());
//                    if (StringUtils.isNotBlank(entry.getValue())) {
//                        sbQuery.append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
//                    }
//                }
//            }
//            if (sbQuery.length() > 0) {
//                sbUrl.append("?").append(sbQuery);
//            }
//        }
//        return sbUrl.toString();
//    }


    // 短信API配置（洛阳云API）
    private static final String SMS_API_HOST = "http://api.guoyangyun.com";
    private static final String SMS_API_PATH = "/api/sms/sendSmsApi.htm";
    private static final String SMS_APP_KEY = "204920215"; // 你的appkey
    private static final String SMS_APP_SECRET = "KOfZfMetxJcykFQu5Zk97W5vvrDQDfr7"; // 你的appsecret
    private static final String SMS_SIGN_NAME = "【2e65b1bb3d054466b82f0c9d125465e2】"; // 平台审核通过的短信签名（必须带【】）


    public void signContract(Long contractId, MultipartFile file) throws IOException {
        // 1. 验证合同是否存在
        Contract contract = contractRepository.findById(contractId)
                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + contractId));

        // 2. 验证合同状态
        if (!ContractStatus.PENDING_CONFIRMATION.name().equals(contract.getStatus())) {
            throw new IllegalArgumentException("合同状态不是待签订，无法执行此操作");
        }

        // 3. 验证文件
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传的文件不能为空");
        }

        // 4. 保存文件
        String fileName = file.getOriginalFilename();
        if (fileName == null || fileName.isEmpty()) {
            fileName = "contract_" + contractId + ".pdf";
        }

        Path filePath = Paths.get(FILE_STORAGE_DIR, fileName);
        Files.createDirectories(filePath.getParent());
        Files.write(filePath, file.getBytes());

        // 5. 创建Document记录
        Document document = new Document();
        document.setType(233);
        document.setContract(contract);
        document.setUploadTime(LocalDateTime.now());
        document.setFilePath(filePath.toString());
        documentRepository.save(document);

        // 新增：发送短信通知（调用修改后的方法）
        sendSmsNotification(contract);

        // 6. 更新合同状态（保持原有注释）
//    contract.setStatus(ContractStatus.CONFIRMED.name());
//    contract.setUpdateTime(LocalDateTime.now());
//    contractRepository.save(contract);
    }


    private void sendSmsNotification(Contract contract) {
        // 1. 获取客户信息和合同ID
        Long contractId = contract.getId();
        if (contractId == null) {
            System.err.println("合同ID为空，无法查询客户信息");
            return;
        }

        // 通过合同ID查询客户（确保获取真实客户）
        Customer customer = customerRepository.findByContractId(contractId)
                .orElseGet(() -> {
                    System.err.println("未查询到合同对应的客户，合同ID: " + contractId);
                    return null;
                });
        if (customer == null || StringUtils.isBlank(customer.getContactInfo())) {
            System.err.println("客户联系信息不完整，无法发送短信");
            return;
        }
        String phone = customer.getContactInfo(); // 客户手机号


        // 2. 准备短信内容（必须包含审核通过的签名）
        String message = SMS_SIGN_NAME + "您的合同（" + contract.getName() + "）已上传，待确认";


        // 3. 构建请求参数（含签名所需参数）
        Map<String, String> params = new HashMap<>();
        params.put("appkey", SMS_APP_KEY); // 必传：appkey
        params.put("mobile", phone); // 必传：手机号
        params.put("content", message); // 必传：短信内容（含签名）
        params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); // 必传：秒级时间戳
        params.put("sign", generateSign(params)); // 核心：生成签名


        // 4. 发送POST请求（适配洛阳云API）
        try {
            // 构建完整请求URL
            String apiUrl = SMS_API_HOST + SMS_API_PATH;
            org.apache.http.client.HttpClient client = org.apache.http.impl.client.HttpClients.createDefault();
            org.apache.http.client.methods.HttpPost post = new org.apache.http.client.methods.HttpPost(apiUrl);

            // 设置请求头
            post.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");

            // 构建表单参数
            java.util.List<org.apache.http.NameValuePair> formParams = new ArrayList<>();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                formParams.add(new org.apache.http.message.BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
            org.apache.http.client.entity.UrlEncodedFormEntity formEntity =
                    new org.apache.http.client.entity.UrlEncodedFormEntity(formParams, "UTF-8");
            post.setEntity(formEntity);

            // 执行请求并处理响应
            org.apache.http.HttpResponse response = client.execute(post);
            if (response.getEntity() != null) {
                String result = org.apache.http.util.EntityUtils.toString(response.getEntity(), "UTF-8");
                System.out.println("洛阳云短信API响应: " + result); // 打印响应便于调试

                // 解析响应（API文档：code=0为成功）
                if (result.contains("\"code\":\"0\"")) {
                    System.out.println("短信发送成功，手机号: " + phone);
                } else {
                    System.err.println("短信发送失败，原因: " + result);
                }
            }
        } catch (Exception e) {
            System.err.println("短信发送异常: " + e.getMessage());
        }
    }


    // 新增：生成洛阳云API要求的签名（核心逻辑）
    private String generateSign(Map<String, String> params) {
        try {
            // 1. 按参数key的ASCII码升序排序（签名生成关键步骤）
            List<String> sortedKeys = new ArrayList<>(params.keySet());
            Collections.sort(sortedKeys); // 必须排序，否则签名验证失败

            // 2. 拼接排序后的参数（key=value&key=value）
            StringBuilder paramStr = new StringBuilder();
            for (String key : sortedKeys) {
                String value = params.get(key);
                if (StringUtils.isNotBlank(value)) { // 跳过空值
                    paramStr.append(key).append("=").append(value).append("&");
                }
            }

            // 3. 拼接appsecret（最后拼接，无&符号）
            paramStr.append("appsecret=").append(SMS_APP_SECRET);

            // 4. MD5加密并转为大写（API要求）
            String sign = org.apache.commons.codec.digest.DigestUtils.md5Hex(paramStr.toString()).toUpperCase();
            System.out.println("签名原始字符串: " + paramStr.toString()); // 调试用：查看签名源串
            System.out.println("生成的sign: " + sign); // 调试用：对比平台工具生成的签名
            return sign;
        } catch (Exception e) {
            System.err.println("签名生成失败: " + e.getMessage());
            return null;
        }
    }


    // 原有URL构建方法（保持不变）
    private String buildApiUrl(String host, String path, Map<String, String> queryParams) throws UnsupportedEncodingException {
        StringBuilder url = new StringBuilder(host);
        if (StringUtils.isNotBlank(path)) {
            url.append(path);
        }

        if (queryParams != null && !queryParams.isEmpty()) {
            StringBuilder query = new StringBuilder();
            for (Map.Entry<String, String> param : queryParams.entrySet()) {
                if (query.length() > 0) {
                    query.append("&");
                }
                query.append(param.getKey()).append("=")
                        .append(URLEncoder.encode(param.getValue(), "UTF-8"));
            }
            url.append("?").append(query);
        }
        return url.toString();
    }

    // 依赖注入方法（保持不变）
    public void setContractRepository(ContractRepository contractRepository) {
        this.contractRepository = contractRepository;
    }

    public void setDocumentRepository(DocumentRepository documentRepository) {
        this.documentRepository = documentRepository;
    }

    // 独立URL构建方法（保持不变）
    private String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
        StringBuilder sbUrl = new StringBuilder(host);
        if (StringUtils.isNotBlank(path)) {
            sbUrl.append(path);
        }
        if (querys != null && !querys.isEmpty()) {
            StringBuilder sbQuery = new StringBuilder();
            for (Map.Entry<String, String> entry : querys.entrySet()) {
                if (sbQuery.length() > 0) {
                    sbQuery.append("&");
                }
                if (StringUtils.isBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue())) {
                    sbQuery.append(entry.getValue());
                }
                if (StringUtils.isNotBlank(entry.getKey())) {
                    sbQuery.append(entry.getKey());
                    if (StringUtils.isNotBlank(entry.getValue())) {
                        sbQuery.append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
                    }
                }
            }
            if (sbQuery.length() > 0) {
                sbUrl.append("?").append(sbQuery);
            }
        }
        return sbUrl.toString();
    }










    /**
     * 获取待客户确认的合同列表
     */
    public List<Contract> getPendingConfirmContracts(Long customerId, int page, int size) {
        // 参数验证
        if (page < 0 || size <= 0) {
            throw new IllegalArgumentException("分页参数错误，page必须>=0，size必须>0");
        }

        // 验证客户是否存在
        Optional<Contract> customerCheck = contractRepository.findById(customerId);
        if (!customerCheck.isPresent()) {
            throw new IllegalArgumentException("客户不存在，ID: " + customerId);
        }

        Pageable pageRequest = PageRequest.of(page, size);
        return contractRepository.findByCustomerIdAndStatus(
                customerId, ContractStatus.PENDING_CONFIRMATION.name(), pageRequest
        ).getContent();
    }

    /**
     * 获取待客户确认的合同详情
     */
    @Transactional
    public Contract getContractForCustomerConfirmation(Long id) {
        Contract contract = contractRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + id));

        // 验证合同状态是否为待确认
        if (!ContractStatus.PENDING_CONFIRMATION.name().equals(contract.getStatus())) {
            throw new IllegalArgumentException("合同状态不是待确认，无法进行此操作");
        }

        // 初始化关联对象
        initializeContractRelations(contract);
        return contract;
    }


    /**
     * 客户确认合同
     */
    @Transactional
    public void confirmContractByCustomer(Long id) {
        Contract contract = contractRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + id));

        // 验证合同状态是否为待确认
        if (!ContractStatus.PENDING_CONFIRMATION.name().equals(contract.getStatus())) {
            throw new IllegalArgumentException("合同状态不是待确认，无法进行此操作");
        }

        // 更新合同状态为已确认
        contract.setStatus(ContractStatus.CONFIRMED.name());
        contract.setUpdateTime(LocalDateTime.now());
        contractRepository.save(contract);

        MilestonePlan milestonePlan=new MilestonePlan();
        milestonePlan.setContractId(Math.toIntExact(contract.getId()));
        milestonePlan.setStatus(1);
        milestonePlanRepository.save(milestonePlan);

        // 创建确认记录
        createConfirmationDocument(contract);
    }

    /**
     * 创建合同确认记录
     */
    private void createConfirmationDocument(Contract contract) {
        Document document = new Document();
        document.setType(234); // 234表示客户确认合同
        document.setContract(contract);
        document.setUploadTime(LocalDateTime.now());
        document.setFilePath("系统自动生成的确认记录");
        documentRepository.save(document);
    }

//    /**
//     * 获取进行中的合同数量
//     */
//    @Transactional(readOnly = true)
//    public Long getOngoingContractCount(Long employeeId) {
//        return contractRepository.countByProjectManagerIdAndStatus(
//                employeeId, ContractStatus.CONFIRMED.name());
//    }
//
//    /**
//     * 获取进行中的合同列表（带分页）
//     */
//    @Transactional(readOnly = true)
//    public Page<Contract> getOngoingContracts(Long managerId, Pageable pageable) {
//        return contractRepository.findByProjectManagerIdAndStatus(
//                managerId, ContractStatus.CONFIRMED.name(), pageable);
//    }

    /**
     * 获取合同进度详情
     */
    @Transactional(readOnly = true)
    public ContractProgressDTO getContractProgress(Long id) {
        Contract contract = contractRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + id));

        // 验证合同状态是否为进行中
        if (!ContractStatus.CONFIRMED.name().equals(contract.getStatus())) {
            throw new IllegalArgumentException("合同状态不是进行中，无法查看进度");
        }

        // 获取里程碑计划
        MilestonePlan milestonePlan = milestonePlanRepository.findByContractId(id)
                .orElseThrow(() -> new IllegalArgumentException("未找到合同里程碑计划"));

        ContractProgressDTO progressDTO = new ContractProgressDTO();
        progressDTO.setContract(contract);
        progressDTO.setMilestoneStatus(milestonePlan.getStatus());
        progressDTO.setDepositDescription(milestonePlan.getDepositStageDesc());
        progressDTO.setExecutionDescription(milestonePlan.getExecutionStageDesc());

        return progressDTO;
    }

    /**
     * 开始履行合同
     */
    @Transactional
    public void startContractExecution(Long id) {
        Contract contract = contractRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + id));

        // 验证合同状态是否为进行中
        if (!ContractStatus.CONFIRMED.name().equals(contract.getStatus())) {
            throw new IllegalArgumentException("合同状态不是进行中，无法开始履行");
        }

        // 获取里程碑计划
        MilestonePlan milestonePlan = milestonePlanRepository.findByContractId(id)
                .orElseThrow(() -> new IllegalArgumentException("未找到合同里程碑计划"));

        // 更新里程碑状态
        if (milestonePlan.getStatus() < 2) {
            milestonePlan.setStatus(2);
            milestonePlan.setUpdateTime(LocalDateTime.now());
            milestonePlanRepository.save(milestonePlan);
        }
    }

    /**
     * 更新定金阶段描述
     */

    /**
     * 更新执行阶段描述
     */
    @Transactional
    public void updateExecutionDescription(Long id, String description) {
        // 处理JSON格式的description参数
        description = processJsonDescription(description);

        MilestonePlan milestonePlan = milestonePlanRepository.findByContractId(id)
                .orElseThrow(() -> new IllegalArgumentException("未找到合同里程碑计划"));

        milestonePlan.setExecutionStageDesc(description);
        milestonePlan.setUpdateTime(LocalDateTime.now());
        milestonePlanRepository.save(milestonePlan);
    }

    @Transactional
    public void updateDepositDescription(Long id, String description) {
        // 处理JSON格式的description参数
        description = processJsonDescription(description);

        MilestonePlan milestonePlan = milestonePlanRepository.findByContractId(id)
                .orElseThrow(() -> new IllegalArgumentException("未找到合同里程碑计划"));

        milestonePlan.setDepositStageDesc(description);
        milestonePlan.setUpdateTime(LocalDateTime.now());
        milestonePlanRepository.save(milestonePlan);
    }

    /**
     * 处理可能是JSON格式的描述字符串，提取实际内容
     * @param description 可能是JSON格式的描述字符串
     * @return 提取后的纯文本描述
     */
    private String processJsonDescription(String description) {
        if (description != null && description.startsWith("{") && description.endsWith("}")) {
            try {
                JSONObject jsonObject = new JSONObject(description);
                if (jsonObject.has("description")) {
                    return jsonObject.getString("description");
                }
            } catch (JSONException e) {
                // 如果解析失败，保持原内容不变
//                log.warn("Failed to parse description as JSON: {}", description, e);
            }
        }
        return description;
    }

    /**
     * 确认归档合同
     */
    @Transactional
    public void archiveContract(Long id) {
        Contract contract = contractRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + id));

        // 更新合同状态为已归档
        contract.setStatus(ContractStatus.ARCHIVED.name());
        contract.setUpdateTime(LocalDateTime.now());
        contractRepository.save(contract);

        // 更新里程碑状态为已完成
        MilestonePlan milestonePlan = milestonePlanRepository.findByContractId(id)
                .orElseThrow(() -> new IllegalArgumentException("未找到合同里程碑计划"));

        milestonePlan.setStatus(4);
        milestonePlan.setUpdateTime(LocalDateTime.now());
        milestonePlanRepository.save(milestonePlan);
    }






    /**
     * 获取进行中的合同列表（带分页），包含里程碑状态
     */
    @Transactional(readOnly = true)
    public Page<Contract> getOngoingContracts(Long managerId, Pageable pageable) {
        // 使用新的查询方法获取合同及里程碑状态
        Page<ContractWithMilestoneDTO> contractDTOs =
                contractRepository.findByProjectManagerIdAndStatusWithMilestone(
                        managerId, ContractStatus.CONFIRMED.name(), pageable);

        // 将DTO转换为Contract对象，并设置milestoneStatus
        return contractDTOs.map(dto -> {
            Contract contract = new Contract();
            contract.setId(dto.getId());
            contract.setStatus(dto.getStatus());
            contract.setName(dto.getName());
            contract.setCreateTime(dto.getCreateTime());
            contract.setUpdateTime(dto.getUpdateTime());
            contract.setProjectManager(dto.getProjectManager());
            contract.setCustomer(dto.getCustomer());
            contract.setMilestoneStatus(dto.getMilestoneStatus() != null ?
                    dto.getMilestoneStatus() : 1); // 默认状态为未开始
            return contract;
        });
    }

    /**
     * 获取进行中的合同数量
     */
    @Transactional(readOnly = true)
    public Long getOngoingContractCount(Long employeeId) {
        // 使用新的统计方法
        return contractRepository.countByProjectManagerIdAndStatusWithMilestone(
                employeeId, ContractStatus.CONFIRMED.name());
    }

    /**
     * 根据ID获取合同，包含里程碑状态
     */
    @Transactional(readOnly = true)
    public Optional<Contract> getContractWithMilestone(Long id) {
        Optional<ContractWithMilestoneDTO> dto =
                contractRepository.findByIdWithMilestone(id);

        if (dto.isPresent()) {
            Contract contract = new Contract();
            contract.setId(dto.get().getId());
            contract.setStatus(dto.get().getStatus());
            contract.setName(dto.get().getName());
            contract.setCreateTime(dto.get().getCreateTime());
            contract.setUpdateTime(dto.get().getUpdateTime());
            contract.setProjectManager(dto.get().getProjectManager());
            contract.setCustomer(dto.get().getCustomer());
            contract.setMilestoneStatus(dto.get().getMilestoneStatus() != null ?
                    dto.get().getMilestoneStatus() : 1);
            return Optional.of(contract);
        }
        return Optional.empty();
    }







    /**
     * 获取顾客进行中的合同列表
     */
    @Transactional(readOnly = true)
    public Page<Contract> getCustomerOngoingContracts(Long customerId, Pageable pageable) {
        Customer customer = customerRepository.findById(customerId)
                .orElseThrow(() -> new IllegalArgumentException("客户不存在，ID: " + customerId));

        return contractRepository.findByCustomerAndStatus(
                customer, ContractStatus.CONFIRMED.name(), pageable);
    }

    /**
     * 获取顾客合同进度详情
     */
    @Transactional(readOnly = true)
    public ContractProgressDTO getCustomerContractProgress(Long id) {
        Contract contract = contractRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + id));

        // 验证合同状态是否为进行中
        if (!ContractStatus.CONFIRMED.name().equals(contract.getStatus())) {
            throw new IllegalArgumentException("合同状态不是进行中，无法查看进度");
        }

        // 获取里程碑计划
        MilestonePlan milestonePlan = milestonePlanRepository.findByContractId(id)
                .orElseThrow(() -> new IllegalArgumentException("未找到合同里程碑计划"));

        ContractProgressDTO progressDTO = new ContractProgressDTO();
        progressDTO.setContract(contract);
        progressDTO.setMilestoneStatus(milestonePlan.getStatus());
        progressDTO.setDepositDescription(milestonePlan.getDepositStageDesc());
        progressDTO.setExecutionDescription(milestonePlan.getExecutionStageDesc());

        return progressDTO;
    }

    /**
     * 更新顾客合同进度
     */
    @Transactional
    public void updateCustomerContractStage(Long id, int newStatus) {
        Contract contract = contractRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + id));

        // 验证合同状态是否为进行中
        if (!ContractStatus.CONFIRMED.name().equals(contract.getStatus())) {
            throw new IllegalArgumentException("合同状态不是进行中，无法更新进度");
        }

        // 获取里程碑计划
        MilestonePlan milestonePlan = milestonePlanRepository.findByContractId(id)
                .orElseThrow(() -> new IllegalArgumentException("未找到合同里程碑计划"));

        // 验证是否可以更新状态
        if (milestonePlan.getStatus() == 2 && newStatus == 3) {
            // 从定金阶段到执行阶段
            milestonePlan.setStatus(newStatus);
            milestonePlan.setUpdateTime(LocalDateTime.now());
            milestonePlanRepository.save(milestonePlan);
        } else if (milestonePlan.getStatus() == 3 && newStatus == 4) {
            // 从执行阶段到已完成
            milestonePlan.setStatus(newStatus);
            milestonePlan.setUpdateTime(LocalDateTime.now());
            milestonePlanRepository.save(milestonePlan);

            // 合同完成后更新合同状态
            contract.setStatus(ContractStatus.COMPLETED.name());
            contract.setUpdateTime(LocalDateTime.now());
            contractRepository.save(contract);
        } else {
            throw new IllegalArgumentException("无法执行此状态更新");
        }
    }




    /**
     * 获取顾客已归档的合同列表
     */
    @Transactional(readOnly = true)
    public Page<Contract> findCustomerArchivedContracts(Long customerId, Pageable pageable) {
        Customer customer = customerRepository.findById(customerId)
                .orElseThrow(() -> new IllegalArgumentException("客户不存在，ID: " + customerId));

        return contractRepository.findByCustomerAndStatus(
                customer, ContractStatus.ARCHIVED.name(), pageable);
    }

    /**
     * 根据合同ID获取里程碑计划
     */
    @Transactional(readOnly = true)
    public MilestonePlan getMilestonePlanByContractId(Long contractId) {
        return milestonePlanRepository.findByContractId(contractId)
                .orElseThrow(() -> new IllegalArgumentException("未找到合同里程碑计划，ID: " + contractId));
    }



    /**
     * 获取项目经理已归档的合同数量
     */
    @Transactional(readOnly = true)
    public Long getArchivedContractCount(Long employeeId) {
        Employee employee = employeeRepository.findById(employeeId)
                .orElseThrow(() -> new IllegalArgumentException("员工不存在，ID: " + employeeId));

        return contractRepository.countByProjectManagerAndStatus(
                employee, ContractStatus.ARCHIVED.name());
    }

    /**
     * 获取项目经理已归档的合同列表（带分页）
     */
    @Transactional(readOnly = true)
    public Page<Contract> getEmployeeArchivedContracts(Long employeeId, Pageable pageable) {
        Employee employee = employeeRepository.findById(employeeId)
                .orElseThrow(() -> new IllegalArgumentException("员工不存在，ID: " + employeeId));

        return contractRepository.findByProjectManagerAndStatus(
                employee, ContractStatus.ARCHIVED.name(), pageable);
    }



    public void completeContractByCustomer(Long contractId) {
        // 检查合同是否存在
        Contract contract = contractRepository.findById(contractId)
                .orElseThrow(() -> new IllegalArgumentException("合同不存在，ID: " + contractId));

        // 更新合同状态为已完成
        contract.setStatus(ContractStatus.ARCHIVED.getCode());

        // 获取或创建里程碑计划（注意：需要将 Long 转为 int）
        Optional<MilestonePlan> optionalPlan = milestonePlanRepository.findByContractId(contractId);

        MilestonePlan milestonePlan;
        if (optionalPlan.isPresent()) {
            milestonePlan = optionalPlan.get();
        } else {
            // 创建新计划时，将 Long 转为 int（需要确保 contractId 在 int 范围内）
            milestonePlan = new MilestonePlan();
            milestonePlan.setContractId(Math.toIntExact(contractId));
            milestonePlan.setStatus(1); // 默认状态：未开始
        }

        // 更新里程碑状态为已完成
        milestonePlan.setStatus(4);

        // 保存更新
        contractRepository.save(contract);
        milestonePlanRepository.save(milestonePlan);
    }

    /**
     * 查询顾客的合同统计数据
     */
    public CustomerContractStatsDTO getCustomerContractStats(Long customerId) {
        CustomerContractStatsDTO stats = new CustomerContractStatsDTO();

        // 1. 待审核合同数：状态为“待顾客审核”
        Long pendingAudit = contractRepository.countByCustomerIdAndStatus(
                customerId, "PENDING_REVIEW"
        );
        stats.setPendingAuditCount(pendingAudit);

        // 2. 进行中的合同数：状态为“已确认”（已确认但未完成）
        Long ongoing = contractRepository.countByCustomerIdAndStatus(
                customerId, "CONFIRMED"
        );
        stats.setOngoingCount(ongoing);

        // 3. 已完成合同数：状态为“已完成”
        Long completed = contractRepository.countByCustomerIdAndStatus(
                customerId, "COMPLETED"
        );
        stats.setCompletedCount(completed);

        // 4. 已归档合同数：状态为“已归档”
        Long archived = contractRepository.countByCustomerIdAndStatus(
                customerId, "ARCHIVED"
        );
        stats.setArchivedCount(archived);

        return stats;
    }

}